package com.foreveross.mofang.serviceconsole.core;

import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.openkoala.koala.auth.core.domain.User;

/**
 * 组（栏目）表
 * 
 * @author fb
 */
@Entity
@Table(name = "MF_GROUP")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "CATEGORY", discriminatorType = DiscriminatorType.STRING)
public class Group extends BaseEntity{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	// 名称
	@NotNull(message = "名称不能为空")
	@Size(max = 30, message = "名称不能超过30个字符")
	@Column(name = "NAME")
	private String name;
	
	@OneToMany(targetEntity = Group.class, mappedBy = "parant", cascade = CascadeType.REMOVE)
	@OrderBy("sortNum ASC")
	private List<Group> children;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "PARANT_ID")
	private Group parant;
	
	// 顺序号
	@Digits(integer = 3, fraction = 2, message = "顺序号必需小数据点后两位!")
	@Column(name = "SORTNUM")
	private Float sortNum;
	
	/**
	 * 获取所有根结点数据 
	 *  
	 */
	public static List<Group> getAllRoots(Class<? extends Group> clazz){
		return getRepository().createJpqlQuery("select g from Group g where TYPE(g) IN (:clazz) and g.parant is EMPTY and g.removed=false order by g.sortNum")
		.addParameter("clazz", clazz)
		.list();
	}
	
	/**
	 * 组保存 
	 */
	public void save(Class<? extends Group> clazz){
		List<Group> group = addRepeatChecking(clazz, "name", this.name);
		
		if (!group.isEmpty()) {
			throw new RuntimeException("组的名称不能重复!");
		}
		
		group = addRepeatChecking(clazz, "sn", this.getSn());
		
		if (!group.isEmpty()) {
			throw new RuntimeException("组的编号不能重复!");
		}
		
		super.save();
	}
	
	
	/**
	 * 组更新
	 */
	public void update(Class<? extends Group> clazz){
		List<Group> group = updateRepeatChecking(clazz, "name", this.name);
		
		if (!group.isEmpty()) {
			throw new RuntimeException("己存在相同名称的组数据!");
		}
		
		group = updateRepeatChecking(clazz, "sn", this.getSn());
		
		if (!group.isEmpty()) {
			throw new RuntimeException("组的编号有重复!");
		}
		
		super.save();
	}
	
	/**
	 * 删除【更改其状态】
	 */
	public void remove(User loginUser) {
		this.setLastUpdate(new Date());
		this.setLastUpdateUser(loginUser);
		this.setRemoved(true);
		super.save();
		
		removes(this);
		Channel.removes(this);
		// 到时还有任务
	}
	
	/**
	 *  逻辑删除指定组下的所有子组
	 *  
	 * @param group
	 */
	public void removes(Group parant) {
		List<Group>  children = parant.getChildren();
		
		if (children == null || children.isEmpty()) {
			return;
		}
		
		for (Group group : children) {
			group.remove(parant.getLastUpdateUser());
		}
	}
	
	private List<Group> addRepeatChecking(Class<? extends Group> clazz, String field, Object value) {
		List<Group> group = null;
		
		// 名称重复校验
		if (parant == null) {
			group = getRepository().createJpqlQuery("select g from Group g where g." + field+ "=:"+field+" and TYPE(g) IN (:clazz)  and g.removed=false  ")
					.addParameter(field, value)
					.addParameter("clazz", clazz)
					.list();
		} else {
			group = getRepository().createJpqlQuery("select g from Group g where g." + field+ "=:"+field+"  and g.parant = :parant  and g.removed=false ")
					.addParameter(field, value)
					.addParameter("parant", parant)
					.list();
		}
		
		return group;
	}
	
	private List<Group> updateRepeatChecking(Class<? extends Group> clazz, String field, Object value) {
		List<Group> group = null;
		
		if (parant == null) {
			group = getRepository().createJpqlQuery("select g from Group g where g." + field + "=:" + field + " and g NOT IN(:group) and TYPE(g) IN (:clazz) and g.removed=false ")
					.addParameter(field, value)
					.addParameter("group", this)
					.addParameter("clazz", clazz)
					.list();
		} else {
			group = getRepository().createJpqlQuery("select g from Group g where g." + field + "=:" + field + "  and g.parant = :parant and g NOT IN(:group)  and g.removed=false ")
					.addParameter(field, value)
					.addParameter("parant", parant)
					.addParameter("group", this)
					.list();
		}
		
		return group;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<Group> getChildren() {
		return children;
	}

	public void setChildren(List<Group> children) {
		this.children = children;
	}

	public Group getParant() {
		return parant;
	}

	public void setParant(Group parant) {
		this.parant = parant;
	}

	public Float getSortNum() {
		return sortNum;
	}

	public void setSortNum(Float sortNum) {
		this.sortNum = sortNum;
	}
	
}
